/*
 * tsk_main.c
 *
 *  Created on: 08.05.2011
 *      Author: Vladimir Meshkov
 *      E-mail: glavmonter@gmail.com
 */

#include <string.h>
#include <stdio.h>
#include <stdint.h>

#include <stm32f10x.h>

#include <FreeRTOS.h>
#include <task.h>
#include <queue.h>
#include <timers.h>
#include <semphr.h>

#include "platform_config.h"

#include "tsk_lcd.h"
#include "tsk_enc.h"
#include "tsk_main.h"
#include "tsk_adc.h"
#include "eeprom.h"
#include "tinymenu.h"
#include "hd44780.h"
#include "texts.cp1251.h"
#include "menu_config.h"

enum
{
	MST_START,
	MST_MENU,
	MST_TRACK,
	MST_REGULATION,
	MST_CURRENT1,
	MST_CURRENT2
} MENU_STATE;


#define stackDepth	(configMINIMAL_STACK_SIZE*5)

extern xQueueHandle xEncMessageQueue;

extern volatile uint16_t ADC1_Data;
extern volatile uint16_t ADC2_Data;
extern volatile uint16_t ADC3_Data;

/*----------------Private Functions--------------------------------------------------------------------------------*/
portTASK_FUNCTION_PROTO( vTaskMain, pvParameters );
portTASK_FUNCTION_PROTO( vTestLCD, pvParameters );

static void vReadEEParameters();
static void vWriteEEParameters();
void menu_select_item(void *arg, char *name);
void vButtonTimerCallback();

/*----------------------------------------------------------------------------------------------------------------------*/

/*----------------EEPROM Values----------------------------------------------------------------------------------*/
uint8_t eeFirstStart	= 0xFF;		// Первый запуск
#define EE_FIRST_START 			0

uint32_t eeTimeOfWork = 0;		// Сколько времени работало
#define EE_TIME_OF_WORK		( EE_FIRST_START + sizeof( eeFirstStart ) )

uint16_t eeNumOfStarts = 0;		// Сколько раз включалось
#define EE_NUM_OF_STARTS	( EE_TIME_OF_WORK + sizeof( eeTimeOfWork ) )

uint8_t eeClear				 = 0;		// Правильно ли выключили
#define EE_CLEAR						( EE_NUM_OF_STARTS + sizeof( eeNumOfStarts ) )

uint8_t eePmtCurrent1 = 0;			// Ток первой лампы
#define EE_CURRENT1				( EE_CLEAR + sizeof( eeClear ) )

uint8_t eePmtCurrent2 = 0;			// Ток второй лампы
#define EE_CURRENT2				( EE_CURRENT1 + sizeof( eePmtCurrent1 ) )

uint32_t eePidProp = 0;					// Коэффициент ПИДа Пропорциональный
#define EE_PID_PROP				( EE_CURRENT2 + sizeof( eePmtCurrent2 ) )

uint32_t eePidInt = 0;						// Коэффициент ПИДа Интегральный
#define EE_PID_INT					( EE_PID_PROP + sizeof( eePidProp ) )

uint32_t eePidDiff = 0;					// Коэффициент ПИДа Дифференциальный
#define EE_PID_DIFF					( EE_PID_INT + sizeof( eePidInt ) )
/*----------------------------------------------------------------------------------------------------------------------*/



void vStartMain( unsigned portBASE_TYPE uxPriority )
{
	vReadEEParameters();

	xTaskCreate( vTestLCD, ( signed portCHAR * ) "test", configMINIMAL_STACK_SIZE, NULL, 0, NULL );
	xTaskCreate( vTaskMain, ( signed portCHAR * ) "Main", stackDepth, NULL, uxPriority, NULL );
}

static void vInitEEFirst()
{
uint8_t buffer[32];
uint16_t i;

	// Очистка EEPROM
	memset( buffer, 0xFF, sizeof( buffer ) );
	for( i = 0; i < 1024; i += 32 )
		sEE_WriteBuffer( buffer, i, sizeof( buffer ) );

	eeFirstStart = 1;
	eeTimeOfWork = 0;
	eeNumOfStarts = 1;
	eePmtCurrent1 = 60;
	eePmtCurrent2 = 60;
	eePidProp = 1;
	eePidInt = 1;
	eePidDiff = 1;

	vWriteEEParameters();
}

static void vReadEEParameters()
{
	eeFirstStart = sEE_ReadByte( EE_FIRST_START );
	if( eeFirstStart == 0xFF )
		vInitEEFirst();

volatile uint16_t NumToRead = 0;
	NumToRead = sizeof( eeTimeOfWork );
	sEE_ReadBuffer( ( uint8_t * ) &eeTimeOfWork, EE_TIME_OF_WORK, ( uint16_t * ) &NumToRead );
	while( NumToRead > 0 ) {}

	NumToRead = sizeof( eeNumOfStarts );
	sEE_ReadBuffer( ( uint8_t * ) &eeNumOfStarts, EE_NUM_OF_STARTS, ( uint16_t * ) &NumToRead );
	while( NumToRead > 0 ) {}

	NumToRead = sizeof( eePmtCurrent1 );
	sEE_ReadBuffer( ( uint8_t * ) &eePmtCurrent1, EE_CURRENT1, ( uint16_t * ) &NumToRead );
	while( NumToRead > 0 ) {}

	NumToRead = sizeof( eePmtCurrent2 );
	sEE_ReadBuffer( ( uint8_t * ) &eePmtCurrent2, EE_CURRENT2, ( uint16_t * ) &NumToRead );
	while( NumToRead > 0 ) {}

	NumToRead = sizeof( eeClear );
	sEE_ReadBuffer( ( uint8_t * ) &eeClear, EE_CLEAR, ( uint16_t * ) &NumToRead );
	while( NumToRead > 0 ) {}

	NumToRead = sizeof( eePidProp );
	sEE_ReadBuffer( ( uint8_t * ) &eePidProp, EE_PID_PROP, ( uint16_t * ) &NumToRead );
	while( NumToRead > 0 ) {}

	NumToRead = sizeof( eePidInt );
	sEE_ReadBuffer( ( uint8_t * ) &eePidInt, EE_PID_INT, ( uint16_t * ) &NumToRead );
	while( NumToRead > 0 ) {}

	NumToRead = sizeof( eePidDiff );
	sEE_ReadBuffer( ( uint8_t * ) &eePidDiff, EE_PID_DIFF, ( uint16_t * ) &NumToRead );
	while( NumToRead > 0 ) {}
}

static void vWriteEEParameters()
{
	sEE_WriteBuffer( ( uint8_t * ) &eeFirstStart, EE_FIRST_START, sizeof ( eeFirstStart ) );
	sEE_WriteBuffer( ( uint8_t * ) &eeTimeOfWork, EE_TIME_OF_WORK, sizeof( eeTimeOfWork ) );
	sEE_WriteBuffer( ( uint8_t * ) &eeNumOfStarts, EE_NUM_OF_STARTS, sizeof( eeNumOfStarts ) );
	sEE_WriteBuffer( ( uint8_t * ) &eeClear, EE_CLEAR, sizeof( eeClear ) );
	sEE_WriteBuffer( ( uint8_t * ) &eePmtCurrent1, EE_CURRENT1, sizeof( eePmtCurrent1 ) );
	sEE_WriteBuffer( ( uint8_t * ) &eePmtCurrent2, EE_CURRENT2, sizeof( eePmtCurrent2 ) );
	sEE_WriteBuffer( ( uint8_t * ) &eePidProp, EE_PID_PROP, sizeof( eePidProp ) );
	sEE_WriteBuffer( ( uint8_t * ) &eePidInt, EE_PID_INT, sizeof( eePidInt ) );
	sEE_WriteBuffer( ( uint8_t * ) &eePidDiff, EE_PID_DIFF, sizeof( eePidDiff ) );
}

void menu_select_item(void *arg, char *name)
{
	int iarg = ( int ) arg;

	printf( "Selected: %s\n", name );
	if( iarg == MENU_RETURN )
		menu_exit( &menu_context );

	if( iarg == MENU_DEXIT_No )
		menu_exit( &menu_context );

// TODO Сделать переход на плавное выключение
	if( iarg == MENU_DEXIT_Ok )
	{
		vTaskEndScheduler();
		PWR_EnterSTOPMode( PWR_Regulator_LowPower, PWR_STOPEntry_WFI );
	}

	if( iarg == MENU_TRACK )
	{
		MENU_STATE = MST_TRACK;
		xLCDSendCmd( CMD_CLEAR, 0 );
	}

	if( iarg == MENU_REGULATION )
	{
		MENU_STATE = MST_REGULATION;
		xLCDSendCmd( CMD_CLEAR, 0 );
	}

	if( iarg == MENU_CURRENT1 )
	{
		MENU_STATE = MST_CURRENT1;
		xLCDSendCmd( CMD_CUR_STATE, LCD_CUR_BLINK );
	}

	if( iarg == MENU_CURRENT2 )
	{
		MENU_STATE = MST_CURRENT2;
		xLCDSendCmd( CMD_CUR_STATE, LCD_CUR_BLINK );
	}
}

void vButtonTimerCallback()
{
	printf( "Long\n" );
	if( ( MENU_STATE == MST_REGULATION ) || ( MENU_STATE == MST_TRACK ) )
	{

		MENU_STATE = MST_MENU;
		menu_enter( &menu_context, &main_menu );
	}

	if( ( MENU_STATE == MST_CURRENT1 ) || ( MENU_STATE == MST_CURRENT2 ) )
	{
		MENU_STATE = MST_MENU;
		xLCDSendCmd( CMD_CUR_STATE, LCD_CUR_NONE );
		menu_exit( &menu_context );
	}
}

portTickType xLastTick = 0;

void vShowMain()
{
// TODO Убрать костыль с очисткой
	xLCDSendCmd( CMD_CLEAR, 0 );

char buffer[20];
uint16_t data1 = 0;
uint16_t data2 = 0;
uint16_t data3 = 0;

	portENTER_CRITICAL();
		data1 = ADC1_Data;
		data2 = ADC2_Data;
		data3 = ADC3_Data;
	portEXIT_CRITICAL();

	float fData1 = data1*3302/4095/310.0f;
	float fData2 = data2*3302/4095/330.0f;

	sprintf( buffer, "%s: %d.%d%s", XVOST, (int) fData1, (int)((fData1 - (int)fData1)*10), MM );
	xLCDDrawText( buffer, Line_1, 0 );

	sprintf( buffer, "%s: %d.%d%s", KOLP, (int) fData2, (int)((fData2 - (int)fData2)*10), MM );
	xLCDDrawText( buffer, Line_2, 0 );

	uint16_t temp;
	temp = (1430 - data3*3300/4095)/4.3f +25;

	sprintf( buffer, "%s: %s", REFERENCE, MM );
	xLCDDrawText( buffer, Line_3, 0 );
	sprintf( buffer, "t:%dC", temp );
	xLCDDrawText( buffer, Line_4, 11 );

	sprintf( buffer, "%s: %\%", VALVE);
	xLCDDrawText( buffer, Line_4, 0 );

	if( MENU_STATE == MST_TRACK )
		xLCDDrawText( "T", Line_4, 19 );
	if( MENU_STATE == MST_REGULATION )
		xLCDDrawText( "R", Line_4, 19 );

	printf( "main\n" );
}

portTASK_FUNCTION( vTaskMain, pvParameters )
{
	( void ) pvParameters;

	xLCDDrawText( "Welcome", Line_1, 0 );
	xLCDDrawText( "FreeRTOS 7.0.0", Line_2, 0 );
	xLCDDrawText( "Vacuumeter", Line_3, 0 );
	xLCDDrawText( "Test...", Line_4, 0 );
	vTaskDelay( 1000 );
	xLCDSendCmd( CMD_CLEAR, 0 );

	vTaskDelay( 100 );
	vStartEncoder( 1 );
	vStartADC( 0 );

	MENU_STATE = MST_MENU;

	menu_enter( &menu_context, &main_menu );

portTickType xLastWakeTime = xTaskGetTickCount();
xEncMessage xMessage;

	for( ; ; )
	{
		xMessage.xEvent = EEvent_None;
		xQueueReceive( xEncMessageQueue, ( void * ) &xMessage, 0 );
//		{
//			switch(  xMessage.xEvent )
//			{
//				case EEvent_CW:
////					printf( "CW:%d\n", ( int ) xMessage.iData );
//					break;
//
//				case EEvent_CCW:
////					printf( "CCW:%d\n", ( int ) xMessage.iData );
//					break;
//
//				case EEvent_Click:
////					printf( "Click\n" );
//					break;
//
//				case EEvent_LongClick:
////					printf( "Long Click\n" );
//					break;
//
//				case EEvent_None:
//					break;
//			}
//		}

		if( MENU_STATE == MST_MENU )
		{
			if( xMessage.xEvent == EEvent_CW )
				menu_next_entry( &menu_context );

			if( xMessage.xEvent == EEvent_CCW )
				menu_prev_entry( &menu_context );
		}

		if( MENU_STATE == MST_MENU )
		{
			if( xMessage.xEvent == EEvent_Click )
				menu_select( &menu_context );
		}
		if( xMessage.xEvent == EEvent_LongClick )
			vButtonTimerCallback();

		if( ( xTaskGetTickCount() - xLastTick ) > 330 )
		{
			xLastTick = xTaskGetTickCount();
			if( ( MENU_STATE == MST_TRACK ) || ( MENU_STATE == MST_REGULATION ) )
				vShowMain();
		}

		vTaskDelayUntil( &xLastWakeTime, 1 );
	}
}

portTASK_FUNCTION( vTestLCD, pvParameters )
{
	( void ) pvParameters;

	for( ; ; )
	{
		vTaskDelay( 300 );
	}
}
